package com.th.coupon.executor.impl;

import com.alibaba.fastjson.JSON;
import com.th.coupon.common.constant.CouponCategory;
import com.th.coupon.common.vo.GoodsInfo;
import com.th.coupon.common.vo.SettlementInfo;
import com.th.coupon.constant.RuleFlag;
import com.th.coupon.executor.AbstractRuleExecutor;
import com.th.coupon.executor.RuleExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 满减与折扣优惠卷 多类别优惠卷规则
 * @author 涂航
 */
@Component
@Slf4j
public class AllminusAndDiscountExecutor extends AbstractRuleExecutor implements RuleExecutor {
    /**
     * 规则类型
     * @return
     */
    @Override
    public RuleFlag ruleConfig() {
        return RuleFlag.ALLMINUS_DISCOUNT_RULE;
    }

    /**
     * 效验商品类型与优惠卷是否匹配
     * 重写该方法 实现多类别优惠卷
     * @param settlementInfo {@link SettlementInfo} 用户传递的结算信息
     * @return
     */
    @Override
    protected Boolean isGoodsTypeSatisfy(SettlementInfo settlementInfo) {
        log.debug("Check Allminus And Discount Is Match Or Not !");
        //获取所有商品的类型
        List<Integer> goodsType =
                settlementInfo.getGoodsInfos().stream().map(GoodsInfo::getType).collect(Collectors.toList());

        List<Integer> templateGoodsType = new ArrayList<>();
        settlementInfo.getCouponAndTemplateInfos().forEach(couponAndTemplateInfo -> {
            templateGoodsType.addAll(JSON.parseObject(couponAndTemplateInfo
                    .getTemplateSdk()
                    .getRule()
                    .getUsage()
                    .getGoodsType(),List.class));
        });

        //如果想使用多类优惠卷，则必须所有的商品类型都包含在里面，即差集为空
        return CollectionUtils.isEmpty(CollectionUtils.subtract(
                goodsType,templateGoodsType
        ));
    }

    @Override
    public SettlementInfo computeRule(SettlementInfo info) {
        //计算总价
        Double goodsSum = retain2Decimals(
                goodsCostSum(info.getGoodsInfos()), 2);
        //效验优惠卷是否可使用
        SettlementInfo settlementInfo = processGoodsTypeNatSatisfy(info, goodsSum);
        //如果不为空说明优惠卷不适合当前商品类型使用
        if(null != settlementInfo){
            log.debug("Allminus And Discount Template Is Not Match To GoodsType !");
            return settlementInfo;
        }
        //判断优惠卷的类型，哪张是满减，哪张是折扣
        SettlementInfo.CouponAndTemplateInfo allminus = null;
        SettlementInfo.CouponAndTemplateInfo discount = null;

        for (SettlementInfo.CouponAndTemplateInfo couponAndTemplateInfo : info.getCouponAndTemplateInfos()) {
            if(CouponCategory.of(couponAndTemplateInfo.getTemplateSdk().getCategory()) ==
            CouponCategory.ALLMINUS){
                allminus = couponAndTemplateInfo;
            }else {
                discount = couponAndTemplateInfo;
            }
        }

        assert null != allminus;
        assert null != discount;

        //当前的优惠卷和满减卷如果不能共用（一起使用），清空优惠卷，返回商品原价
        if(!isTemplateCanShared(allminus,discount)){
            log.debug("Current Allminus And Discount Can Not Shared !");
            info.setCost(goodsSum);
            info.setCouponAndTemplateInfos(Collections.emptyList());
            return info;
        }

        List<SettlementInfo.CouponAndTemplateInfo> ctInfos = new ArrayList<>();
        //满减
        //基本达到值
        Double allminusBase = Double.valueOf(allminus.getTemplateSdk().getRule().getDiscount().getBase());
        //减去金额
        Double allminusQuota = Double.valueOf(allminus.getTemplateSdk().getRule().getDiscount().getQuota());
        //最终的价格
        Double targetSum = goodsSum;
        if(targetSum >= allminusBase){
            targetSum -= allminusQuota;
            ctInfos.add(allminus);
        }
        //折扣
        //减去金额 折扣 额度
        Double discountQuota = Double.valueOf(discount.getTemplateSdk().getRule().getDiscount().getQuota());
        targetSum *= (discountQuota*1.0)/100;
        ctInfos.add(discount);

        info.setCouponAndTemplateInfos(ctInfos);
        info.setCost(retain2Decimals(targetSum > minCost() ?targetSum : minCost(),2));

        log.debug("Use Allminus And Discount Coupon Make Goods Cost From {} To {}",goodsSum,info.getCost());

        return info;
    }

    /**
     * 去效验当前的优惠卷是否可以共用
     * @param allminus
     * @param discount
     * @return
     */
    private Boolean isTemplateCanShared(SettlementInfo.CouponAndTemplateInfo allminus,
                                        SettlementInfo.CouponAndTemplateInfo discount){
        //补充优惠卷key
        String allminusKey = allminus.getTemplateSdk().getKey()
                + String.format("%04d",allminus.getTemplateSdk().getId());
        String discountKey = discount.getTemplateSdk().getKey()
                + String.format("%04d",discount.getTemplateSdk().getId());

        List<String> allShareKeysForAllminus = new ArrayList<String>();
        allShareKeysForAllminus.add(allminusKey);
        allShareKeysForAllminus.addAll(JSON.parseObject(
                allminus.getTemplateSdk().getRule().getWeight(),List.class
        ));

        List<String> allShareKeysForDiscountKey = new ArrayList<String>();
        allShareKeysForDiscountKey.add(discountKey);
        allShareKeysForDiscountKey.addAll(JSON.parseObject(
                discount.getTemplateSdk().getRule().getWeight(),List.class
        ));

        //判断两种类型的优惠卷是否可以互相根据weight 包含使用
        return CollectionUtils.isSubCollection(Arrays.asList(allminusKey,discountKey),allShareKeysForAllminus)
                || CollectionUtils.isSubCollection(Arrays.asList(allminusKey,discountKey),allShareKeysForDiscountKey);
    }
}
